import { XMLParser, XMLBuilder } from 'fast-xml-parser'

// Graph JSON 类型定义（基于 X6）
export interface GraphNode {
  id: string
  shape: string
  x?: number
  y?: number
  width?: number
  height?: number
  label?: string
  attrs?: Record<string, any>
  [key: string]: any
}

export interface GraphEdge {
  id: string
  shape: string
  source: string | { cell: string; port?: string }
  target: string | { cell: string; port?: string }
  vertices?: Array<{ x: number; y: number }>
  [key: string]: any
}

export interface GraphJSON {
  cells: Array<GraphNode | GraphEdge>
}

// BPMN XML 类型定义
export interface BPMNDefinitions {
  'bpmn2:definitions': {
    '@_xmlns:bpmn2'?: string
    '@_xmlns:bpmndi'?: string
    '@_xmlns:dc'?: string
    '@_xmlns:di'?: string
    '@_id'?: string
    '@_targetNamespace'?: string
    'bpmn2:process'?: BPMNProcess
    'bpmndi:BPMNDiagram'?: BPMNDiagram
  }
}

export interface BPMNProcess {
  '@_id': string
  '@_name'?: string
  'bpmn2:startEvent'?: BPMNStartEvent | BPMNStartEvent[]
  'bpmn2:endEvent'?: BPMNEndEvent | BPMNEndEvent[]
  'bpmn2:task'?: BPMNTask | BPMNTask[]
  'bpmn2:sequenceFlow'?: BPMNSequenceFlow | BPMNSequenceFlow[]
  [key: string]: any
}

export interface BPMNStartEvent {
  '@_id': string
  '@_name'?: string
}

export interface BPMNEndEvent {
  '@_id': string
  '@_name'?: string
}

export interface BPMNTask {
  '@_id': string
  '@_name'?: string
}

export interface BPMNSequenceFlow {
  '@_id': string
  '@_sourceRef': string
  '@_targetRef': string
  '@_name'?: string
}

export interface BPMNDiagram {
  '@_id': string
  'bpmndi:BPMNPlane'?: {
    '@_id': string
    'bpmndi:BPMNShape'?: BPMNShape | BPMNShape[]
    'bpmndi:BPMNEdge'?: BPMNEdge | BPMNEdge[]
  }
}

export interface BPMNShape {
  '@_id': string
  '@_bpmnElement': string
  'dc:Bounds'?: {
    '@_x': number
    '@_y': number
    '@_width': number
    '@_height': number
  }
}

export interface BPMNEdge {
  '@_id': string
  '@_bpmnElement': string
  'di:waypoint'?: Array<{
    '@_x': number
    '@_y': number
  }>
}

// 节点形状到 BPMN 元素类型的映射
const shapeToBPMNType: Record<string, string> = {
  'custom-rect-start': 'startEvent',
  'custom-rect-end': 'endEvent',
  'custom-rect-task': 'task',
  'custom-rect-chart': 'task',
}

// BPMN 元素类型到节点形状的映射
const bpmnTypeToShape: Record<string, string> = {
  startEvent: 'custom-rect-start',
  endEvent: 'custom-rect-end',
  task: 'custom-rect-task',
  userTask: 'custom-rect-task',
  serviceTask: 'custom-rect-task',
}

/**
 * 将 Graph JSON 转换为 BPMN XML
 */
export function graphJSONToBPMNXML(graphJson: GraphJSON): string {
  const nodes = graphJson.cells.filter(
    (cell): cell is GraphNode => 'x' in cell || 'y' in cell
  )
  const edges = graphJson.cells.filter(
    (cell): cell is GraphEdge => 'source' in cell && 'target' in cell
  )

  const processId = 'Process_1'
  const process: BPMNProcess = {
    '@_id': processId,
    '@_name': 'Process',
  }

  // 转换节点
  const startEvents: BPMNStartEvent[] = []
  const endEvents: BPMNEndEvent[] = []
  const tasks: BPMNTask[] = []
  const shapes: BPMNShape[] = []

  nodes.forEach((node) => {
    const bpmnType = shapeToBPMNType[node.shape] || 'task'
    const bpmnId = node.id || `Element_${Date.now()}_${Math.random()}`
    const name = node.label || ''

    if (bpmnType === 'startEvent') {
      startEvents.push({
        '@_id': bpmnId,
        '@_name': name,
      })
    } else if (bpmnType === 'endEvent') {
      endEvents.push({
        '@_id': bpmnId,
        '@_name': name,
      })
    } else {
      tasks.push({
        '@_id': bpmnId,
        '@_name': name,
      })
    }

    // 添加图形信息
    shapes.push({
      '@_id': `${bpmnId}_di`,
      '@_bpmnElement': bpmnId,
      'dc:Bounds': {
        '@_x': node.x || 0,
        '@_y': node.y || 0,
        '@_width': node.width || 100,
        '@_height': node.height || 80,
      },
    })
  })

  if (startEvents.length > 0) {
    process['bpmn2:startEvent'] = startEvents.length === 1 ? startEvents[0] : startEvents
  }
  if (endEvents.length > 0) {
    process['bpmn2:endEvent'] = endEvents.length === 1 ? endEvents[0] : endEvents
  }
  if (tasks.length > 0) {
    process['bpmn2:task'] = tasks.length === 1 ? tasks[0] : tasks
  }

  // 转换边
  const sequenceFlows: BPMNSequenceFlow[] = []
  const bpmnEdges: BPMNEdge[] = []

  edges.forEach((edge) => {
    const sourceId = typeof edge.source === 'string' ? edge.source : edge.source.cell
    const targetId = typeof edge.target === 'string' ? edge.target : edge.target.cell
    const flowId = edge.id || `Flow_${Date.now()}_${Math.random()}`

    sequenceFlows.push({
      '@_id': flowId,
      '@_sourceRef': sourceId,
      '@_targetRef': targetId,
      '@_name': edge.label || '',
    })

    // 添加边的图形信息
    const waypoints: Array<{ '@_x': number; '@_y': number }> = []
    if (edge.vertices && edge.vertices.length > 0) {
      edge.vertices.forEach((vertex) => {
        waypoints.push({
          '@_x': vertex.x,
          '@_y': vertex.y,
        })
      })
    }

    bpmnEdges.push({
      '@_id': `${flowId}_di`,
      '@_bpmnElement': flowId,
      'di:waypoint': waypoints.length > 0 ? waypoints : undefined,
    })
  })

  if (sequenceFlows.length > 0) {
    process['bpmn2:sequenceFlow'] =
      sequenceFlows.length === 1 ? sequenceFlows[0] : sequenceFlows
  }

  // 构建 BPMN 定义
  const definitions: BPMNDefinitions = {
    'bpmn2:definitions': {
      '@_xmlns:bpmn2': 'http://www.omg.org/spec/BPMN/20100524/MODEL',
      '@_xmlns:bpmndi': 'http://www.omg.org/spec/BPMN/20100524/DI',
      '@_xmlns:dc': 'http://www.omg.org/spec/DD/20100524/DC',
      '@_xmlns:di': 'http://www.omg.org/spec/DD/20100524/DI',
      '@_id': 'Definitions_1',
      '@_targetNamespace': 'http://bpmn.io/schema/bpmn',
      'bpmn2:process': process,
      'bpmndi:BPMNDiagram': {
        '@_id': 'BPMNDiagram_1',
        'bpmndi:BPMNPlane': {
          '@_id': 'BPMNPlane_1',
          'bpmndi:BPMNShape': shapes.length === 1 ? shapes[0] : shapes,
          'bpmndi:BPMNEdge': bpmnEdges.length === 1 ? bpmnEdges[0] : bpmnEdges,
        },
      },
    },
  }

  // 使用 XMLBuilder 构建 XML
  const builder = new XMLBuilder({
    attributeNamePrefix: '@_',
    ignoreAttributes: false,
    format: true,
    indentBy: '  ',
    suppressEmptyNode: true,
  })

  return builder.build(definitions)
}

/**
 * 将 BPMN XML 转换为 Graph JSON
 */
export function bpmnXMLToGraphJSON(bpmnXml: string): GraphJSON {
  const parser = new XMLParser({
    attributeNamePrefix: '@_',
    ignoreAttributes: false,
    parseNodeValue: true,
    parseAttributeValue: true,
    trimValues: true,
    ignoreNameSpace: false,
  })

  const parsed = parser.parse(bpmnXml) as BPMNDefinitions
  const definitions = parsed['bpmn2:definitions']
  const process = definitions?.['bpmn2:process']
  const diagram = definitions?.['bpmndi:BPMNDiagram']
  const plane = diagram?.['bpmndi:BPMNPlane']

  const cells: Array<GraphNode | GraphEdge> = []

  if (!process) {
    return { cells: [] }
  }

  // 创建元素 ID 到图形信息的映射
  const shapeMap = new Map<string, BPMNShape>()
  const shapes = plane?.['bpmndi:BPMNShape']
  if (shapes) {
    const shapeArray = Array.isArray(shapes) ? shapes : [shapes]
    shapeArray.forEach((shape) => {
      shapeMap.set(shape['@_bpmnElement'], shape)
    })
  }

  const edgeMap = new Map<string, BPMNEdge>()
  const edges = plane?.['bpmndi:BPMNEdge']
  if (edges) {
    const edgeArray = Array.isArray(edges) ? edges : [edges]
    edgeArray.forEach((edge) => {
      edgeMap.set(edge['@_bpmnElement'], edge)
    })
  }

  // 转换开始事件
  const startEvents = process['bpmn2:startEvent']
  if (startEvents) {
    const eventArray = Array.isArray(startEvents) ? startEvents : [startEvents]
    eventArray.forEach((event) => {
      const shape = shapeMap.get(event['@_id'])
      const bounds = shape?.['dc:Bounds']
      const nodeShape = bpmnTypeToShape['startEvent'] || 'custom-rect-start'

      cells.push({
        id: event['@_id'],
        shape: nodeShape,
        x: bounds?.['@_x'] || 100,
        y: bounds?.['@_y'] || 100,
        width: bounds?.['@_width'] || 66,
        height: bounds?.['@_height'] || 36,
        label: event['@_name'] || '开始',
      })
    })
  }

  // 转换结束事件
  const endEvents = process['bpmn2:endEvent']
  if (endEvents) {
    const eventArray = Array.isArray(endEvents) ? endEvents : [endEvents]
    eventArray.forEach((event) => {
      const shape = shapeMap.get(event['@_id'])
      const bounds = shape?.['dc:Bounds']
      const nodeShape = bpmnTypeToShape['endEvent'] || 'custom-rect-end'

      cells.push({
        id: event['@_id'],
        shape: nodeShape,
        x: bounds?.['@_x'] || 100,
        y: bounds?.['@_y'] || 100,
        width: bounds?.['@_width'] || 66,
        height: bounds?.['@_height'] || 36,
        label: event['@_name'] || '结束',
      })
    })
  }

  // 转换任务
  const tasks = process['bpmn2:task']
  if (tasks) {
    const taskArray = Array.isArray(tasks) ? tasks : [tasks]
    taskArray.forEach((task) => {
      const shape = shapeMap.get(task['@_id'])
      const bounds = shape?.['dc:Bounds']
      const nodeShape = bpmnTypeToShape['task'] || 'custom-rect-task'

      cells.push({
        id: task['@_id'],
        shape: nodeShape,
        x: bounds?.['@_x'] || 100,
        y: bounds?.['@_y'] || 100,
        width: bounds?.['@_width'] || 66,
        height: bounds?.['@_height'] || 36,
        label: task['@_name'] || '任务',
      })
    })
  }

  // 转换序列流（边）
  const sequenceFlows = process['bpmn2:sequenceFlow']
  if (sequenceFlows) {
    const flowArray = Array.isArray(sequenceFlows) ? sequenceFlows : [sequenceFlows]
    flowArray.forEach((flow) => {
      const edge = edgeMap.get(flow['@_id'])
      const waypoints = edge?.['di:waypoint']
      const vertices =
        waypoints && Array.isArray(waypoints)
          ? waypoints.map((wp) => ({
              x: wp['@_x'],
              y: wp['@_y'],
            }))
          : undefined

      cells.push({
        id: flow['@_id'],
        shape: 'edge',
        source: flow['@_sourceRef'],
        target: flow['@_targetRef'],
        label: flow['@_name'] || '',
        vertices,
      })
    })
  }

  return { cells }
}

/**
 * 导出 Graph JSON 为 BPMN XML 文件
 */
export function exportGraphToBPMN(graphJson: GraphJSON, filename = 'process.bpmn'): void {
  const xml = graphJSONToBPMNXML(graphJson)
  const blob = new Blob([xml], { type: 'application/xml' })
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  link.click()
  URL.revokeObjectURL(url)
}

/**
 * 从 BPMN XML 文件导入 Graph JSON
 */
export function importBPMNToGraph(file: File): Promise<GraphJSON> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      try {
        const xml = e.target?.result as string
        const graphJson = bpmnXMLToGraphJSON(xml)
        resolve(graphJson)
      } catch (error) {
        reject(error)
      }
    }
    reader.onerror = reject
    reader.readAsText(file)
  })
}

